package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.business.rule.BusinessRuleLogService;
import com.xbongbong.paas.business.rule.RuleBusinessLogger;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasFormSubDataEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.model.PaasFormSubDataEsModel;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.BusinessRuleExecuteEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.RuleOperationEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.ComplexFormatHelp;
import com.xbongbong.paas.help.FormDataHelp;
import com.xbongbong.paas.redis.PaasRedisLock;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.help.SerialNoHelp;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.PaasProcessTemplateModel;
import com.xbongbong.paas.pojo.OperationsPojo;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataDeleteBatchDTO;
import com.xbongbong.paas.pojo.vo.FormDataDeleteBatchVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.BusinessRuleAdvancedService;
import com.xbongbong.paas.service.BusinessRuleService;
import com.xbongbong.paas.service.BusinessRuleSimpleService;
import com.xbongbong.paas.service.PaasFormDataService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.businessrule.pojo.BusinessRuleDataPojo;
import com.xbongbong.pro.businessrule.pojo.dto.OperationDTO;
import com.xbongbong.pro.businessrulelog.pojo.BusinessRuleLogSaveDTO;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.businessrule.enums.RuleVersionEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.form.pojo.RuleTargetPojo;
import com.xbongbong.pro.log.pojo.dto.RuleBusinessLogDTO;
import com.xbongbong.pro.script.pojo.dto.BusinessRuleSetWhiteListDTO;
import com.xbongbong.pro.script.pojo.vo.ScriptVO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.WorkOrderEntity;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.help.PublicSeniorRuleHelp;
import com.xbongbong.saas.model.AssembleModel;
import com.xbongbong.saas.model.BomBillModel;
import com.xbongbong.saas.model.ClueModel;
import com.xbongbong.saas.model.CommunicatePlanModel;
import com.xbongbong.saas.model.CompetitorModel;
import com.xbongbong.saas.model.ContactModel;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.CostAdjustModel;
import com.xbongbong.saas.model.CustomerCommunicateModel;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.InstockModel;
import com.xbongbong.saas.model.InventoryModel;
import com.xbongbong.saas.model.InvoiceModel;
import com.xbongbong.saas.model.MarketActivityModel;
import com.xbongbong.saas.model.OpportunityModel;
import com.xbongbong.saas.model.OutstockModel;
import com.xbongbong.saas.model.PaasFormDataModel;
import com.xbongbong.saas.model.PaasFormSubDataModel;
import com.xbongbong.saas.model.PayPlanModel;
import com.xbongbong.saas.model.PayPlanSheetModel;
import com.xbongbong.saas.model.PaymentModel;
import com.xbongbong.saas.model.PaymentSheetModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.ProductionOrderModel;
import com.xbongbong.saas.model.PurchaseInvoiceModel;
import com.xbongbong.saas.model.PurchaseModel;
import com.xbongbong.saas.model.QuotationModel;
import com.xbongbong.saas.model.RefundModel;
import com.xbongbong.saas.model.ReturnedPurchaseModel;
import com.xbongbong.saas.model.SupplierCommunicateModel;
import com.xbongbong.saas.model.SupplierContactModel;
import com.xbongbong.saas.model.SupplierModel;
import com.xbongbong.saas.model.TransferModel;
import com.xbongbong.saas.model.WarehouseModel;
import com.xbongbong.saas.model.WorkOrderModel;
import com.xbongbong.saas.service.ListBatchService;
import com.xbongbong.saas.service.ScoreCalculateService;
import com.xbongbong.sys.domain.entity.CompanyConfigEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.util.AddressUtil;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.xbongbong.paas.enums.IndexTypeEnum.IDX_SAAS_CUSTOMER_COMMUNICATE;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author: wufeng
 * @date: 2019/1/3 10:34
 * @desrcption: 业务规则
 */
@Component
public class BusinessRuleServiceImpl implements BusinessRuleService {

    private static final Logger LOG = LoggerFactory.getLogger(BusinessRuleServiceImpl.class);

    @Resource
    private PaasFormDataService paasFormDataService;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PaasFormDataModel paasFormDataModel;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private ContactModel contactModel;
    @Resource
    private CustomerCommunicateModel customerCommunicateModel;
    @Resource
    private CommunicatePlanModel communicatePlanModel;
    @Resource
    private OpportunityModel opportunityModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private RefundModel refundModel;
    @Resource
    private QuotationModel quotationModel;
    @Resource
    private SupplierModel supplierModel;
    @Resource
    private SupplierContactModel supplierContactModel;
    @Resource
    private SupplierCommunicateModel supplierCommunicateModel;
    @Resource
    private PurchaseModel purchaseModel;
    @Resource
    private ReturnedPurchaseModel returnedPurchaseModel;
    @Resource
    private BomBillModel bomBillModel;
    @Resource
    private ProductionOrderModel productionOrderModel;
    @Resource
    private AssembleModel assembleModel;
    @Resource
    private InstockModel instockModel;
    @Resource
    private OutstockModel outstockModel;
    @Resource
    private InventoryModel inventoryModel;
    @Resource
    private TransferModel transferModel;
    @Resource
    private WarehouseModel warehouseModel;
    @Resource
    private PaymentModel paymentModel;
    @Resource
    private PaymentSheetModel paymentSheetModel;
    @Resource
    private PayPlanModel payPlanModel;
    @Resource
    private PayPlanSheetModel payPlanSheetModel;
    @Resource
    private InvoiceModel invoiceModel;
    @Resource
    private PurchaseInvoiceModel purchaseInvoiceModel;
    @Resource
    private WorkOrderModel workOrderModel;
    @Resource
    @Lazy
    private RuleBusinessLogger ruleBusinessLogger;
    @Resource
    private ListBatchService listBatchService;
    @Resource
    private ProductModel productModel;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private PaasProcessTemplateModel paasProcessTemplateModel;
    @Resource
    private ComplexFormatHelp complexFormatHelp;
    @Resource
    private SerialNoHelp serialNoHelp;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private BusinessRuleLogService businessRuleLogService;
    @Resource
    private BusinessRuleSimpleService businessRuleSimpleService;
    @Resource
    private BusinessRuleAdvancedService businessRuleAdvancedService;
    @Resource
    private PaasFormSubDataEsModel paasFormSubDataEsModel;
    @Resource
    private PaasFormSubDataModel paasFormSubDataModel;
    @Resource
    private PaasRedisLock paasRedisLock;
    @Resource
    private ClueModel clueModel;
    @Resource
    private MarketActivityModel marketActivityModel;
    @Resource
    private ScoreCalculateService scoreCalculateService;
    @Resource
    private CostAdjustModel costAdjustModel;
    @Resource
    private FormDataHelp formDataHelp;
    @Resource
    private PublicSeniorRuleHelp publicSeniorRuleHelp;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private CompetitorModel competitorModel;


    @Override
    public void addAndUpdate(OperationDTO  operationDTO) throws XbbException{
        String corpid = operationDTO.getCorpid();
        RuleTargetPojo ruleTargetPojo = operationDTO.getTarget();
        String formIdKey = corpid + StringConstant.UNDER_LINE +
                ruleTargetPojo.getLinkSaasMark() + StringConstant.UNDER_LINE + ruleTargetPojo.getLinkBusinessType() +
                StringConstant.UNDER_LINE + ruleTargetPojo.getFormId();
        // 以表单id和业务规则id为key，判断是否需要加锁；
        String businessRuleKey = formIdKey + StringConstant.UNDER_LINE + operationDTO.getBusinessRuleInfoId();
        String requestId = UUID.randomUUID().toString();
        try {
            List<OperationsPojo> operations = operationDTO.getOperations();
            // 获取explains
            setExplainMap(operationDTO);

            String redisBusinessRuleKey = paasRedisHelper.getValue(RedisPrefixConstant.BUSINESS_RULE_ADD_AND_UPDATE, businessRuleKey);
            if(Objects.nonNull(operations) && Objects.equals(SaasMarkEnum.PAAS.getCode(), operationDTO.getTarget().getLinkSaasMark())){
                if (Objects.isNull(redisBusinessRuleKey) || Objects.equals("1", redisBusinessRuleKey)) {

                    // 加锁：由公司id和表单id、业务规则id，拼合而成一个key，用于拦截“更新和插入数据”、“仅更新”，避免导入时数据数据混乱
                    // 出现问题的情况如下：如果是“更新和插入数据”操作，且目标表单没有符合条件的数据，并且是导入或者批量进来的，当前表单的数据会有多条符合条件，那么业务规则会先执行插入操作，后续进来的将执行的更新操作
                    // 期望是只有一条数据，不应该出现多条数据，如果操作中有计算操作，其最终值应该保证正确
                    // 不加锁的情况下，即错误的时候如果是“更新和插入数据”操作的话，会出现多条数据，且更新的值如果含有计算也会存在问题；
                    // 不加锁的情况下，即错误的时候如果是“仅更新”操作的话，更新的值如果含有计算也会存在问题；
                    long startTime = DateTimeUtil.getLong();
                    if (paasRedisLock.tryLock(RedisPrefixConstant.BUSINESS_RULE_ADD_AND_UPDATE_LOCK, businessRuleKey, requestId, PaasRedisLock.TIMEOUT, PaasRedisLock.TIMEOUT, TimeUnit.MINUTES)) {
                        long endTime = DateTimeUtil.getLong();
                        long time = endTime - startTime;
                        LOG.info("addAndUpdate businessRule lock customer time， key:" + businessRuleKey + "-》time：" + time);
                        paasRedisHelper.setValue(RedisPrefixConstant.BUSINESS_RULE_ADD_AND_UPDATE, businessRuleKey, "1", TimeConstant.SECONDS_PER_MINUTE);
                        addAndUpdateOperator(operationDTO);
                        paasRedisLock.unlock(RedisPrefixConstant.BUSINESS_RULE_ADD_AND_UPDATE_LOCK, businessRuleKey, requestId);
                        paasRedisHelper.setValue(RedisPrefixConstant.BUSINESS_RULE_ADD_AND_UPDATE, businessRuleKey, "0", TimeConstant.SECONDS_PER_MINUTE);

                    } else {
                        // 记录日志
                        LOG.warn("addAndUpdate get lock failed key：" + businessRuleKey);
                        setLog(operationDTO, BusinessRuleExecuteEnum.GET_LOCK_ERROR.getMessage(), BusinessRuleExecuteEnum.GET_LOCK_ERROR.getCode(),
                                RuleOperationEnum.ONLY_UPDATE.getType(), 1, 0);

                    }
                } else {
                    paasRedisHelper.setValue(RedisPrefixConstant.BUSINESS_RULE_ADD_AND_UPDATE, businessRuleKey, "1", TimeConstant.SECONDS_PER_MINUTE);
                    addAndUpdateOperator(operationDTO);
                    paasRedisHelper.setValue(RedisPrefixConstant.BUSINESS_RULE_ADD_AND_UPDATE, businessRuleKey, "0", TimeConstant.SECONDS_PER_MINUTE);

                }
            }
        } catch (XbbException e) {
            paasRedisLock.unlock(RedisPrefixConstant.BUSINESS_RULE_ADD_AND_UPDATE_LOCK, businessRuleKey, requestId);
            throw e;
        } catch (Exception e){
            paasRedisLock.unlock(RedisPrefixConstant.BUSINESS_RULE_ADD_AND_UPDATE_LOCK, businessRuleKey, requestId);
            LOG.error("AddAndUpdateHelp.addAndUpdate 业务规则添加和更新出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    private void addAndUpdateOperator(OperationDTO operationDTO) throws XbbException{
        try {
            BusinessRuleDataPojo businessRuleDataPojo= getDataList(operationDTO);
            List<PaasFormDataEntityExt> formDataList = businessRuleDataPojo.getFormDataList();
            if (CollectionsUtil.isNotEmpty(formDataList)) {
                // 更新操作
                onlyUpdate(operationDTO, businessRuleDataPojo);
            } else {
                // 插入操作
                onlyAdd(operationDTO);
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e){
            LOG.error("AddAndUpdateHelp.addAndUpdateOperator 业务规则添加和更新出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

    }

    @Override
    public void onlyAdd(OperationDTO operationDTO) throws XbbException {
        try {
            if(Objects.nonNull(operationDTO)){
                RuleTargetPojo ruleTargetPojo = operationDTO.getTarget();
                Long formId = ruleTargetPojo.getFormId();
                String corpId = operationDTO.getCorpid();
                List<OperationsPojo> operations = operationDTO.getOperations();
                if(Objects.nonNull(operations)){
                    setExplainMap(operationDTO);
                    PaasFormEntityExt paasFormEntityExt = new PaasFormEntityExt();
                    if (Objects.equals(ruleTargetPojo.getLinkBusinessType(), XbbRefTypeEnum.WORK_ORDER.getCode())) {
                        WorkOrderEntity workOrderEntity = workOrderModel.getByKey(formId, corpId);
                        BeanUtil.copyProperties(workOrderEntity, paasFormEntityExt);
                    } else {
                        paasFormEntityExt = paasFormModel.getByKey(formId, corpId);
                    }
                    if(Objects.nonNull(paasFormEntityExt)){
                        Integer type = operationDTO.getType();
                        JSONArray insertList;
                        if (Objects.equals(RuleVersionEnum.SIMPLE.getType(), type)) {
                            // 简易版
                            insertList = complexFormatHelp.getInsertList(operationDTO);
                        } else {
                            // 公式版
                            insertList = complexFormatHelp.getInsertListByFormula(operationDTO);
                        }
                        if (Objects.isNull(insertList) || insertList.isEmpty()) {
                            return;
                        }
                        // 获取编号
                        List<String> serialNoList = serialNoHelp.getSerialNoListByFormId(corpId, formId, operationDTO.getTargetExplain(), insertList.size());
                        for (int i = 0; i < insertList.size(); i++) {
                            JSONObject jsonObject = insertList.getJSONObject(i);
                            String serialNo = "";
                            if (CollectionsUtil.isNotEmpty(serialNoList)) {
                                serialNo = serialNoList.get(i);
                            }
                            insert(operationDTO, paasFormEntityExt, jsonObject, serialNo);
                        }
                        setLog(operationDTO, BusinessRuleExecuteEnum.SUCCESS.getMessage(), BusinessRuleExecuteEnum.SUCCESS.getCode(), RuleOperationEnum.ONLY_INSERT.getType(), insertList.size(), 1);
                    }
                }
            }
        } catch (XbbException e) {
          throw e;
        } catch (Exception e){
            LOG.error("onlyAddHelp.onlyAdd业务规则仅添加出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    private void insert(OperationDTO operationDTO, PaasFormEntityExt paasFormEntityExt, JSONObject jsonObject, String serialNo) throws XbbException {
        RuleTargetPojo ruleTargetPojo = operationDTO.getTarget();
        Long appId = paasFormEntityExt.getAppId();
        Long formId = paasFormEntityExt.getId();
        Long menuId = paasFormEntityExt.getMenuId();
        FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
        formDataAddDTO.setCorpid(operationDTO.getCorpid());
        formDataAddDTO.setLoginUser(operationDTO.getLoginUser());
        formDataAddDTO.setUserId(operationDTO.getUserId());
        formDataAddDTO.setLoginUserName(operationDTO.getLoginUserName());
        formDataAddDTO.setHttpHeader(operationDTO.getHttpHeader());
        formDataAddDTO.setPlatform(operationDTO.getPlatform());
        formDataAddDTO.setLocale(operationDTO.getLocale());
        formDataAddDTO.setAppId(appId);
        formDataAddDTO.setFormId(formId);
        formDataAddDTO.setMenuId(menuId);
        formDataAddDTO.setSerialNo(serialNo);
        formDataAddDTO.setSaasMark(ruleTargetPojo.getLinkSaasMark());
        formDataAddDTO.setBusinessType(ruleTargetPojo.getLinkBusinessType());
        formDataAddDTO.setDataList(jsonObject);
        formDataAddDTO.setIsBusinessRule(1);
        paasFormDataService.add(formDataAddDTO);
        LOG.info("businessRule onlyAdd add success");
    }

    @Override
    public void onlyUpdate(OperationDTO operationDTO, BusinessRuleDataPojo businessRuleDataPojo) throws XbbException {
        RuleTargetPojo ruleTargetPojo = operationDTO.getTarget();
        String corpid = operationDTO.getCorpid();
        String key = corpid + StringConstant.UNDER_LINE +
                ruleTargetPojo.getLinkSaasMark() + StringConstant.UNDER_LINE + ruleTargetPojo.getLinkBusinessType() +
                StringConstant.UNDER_LINE + ruleTargetPojo.getFormId();
        String requestId = UUID.randomUUID().toString();
        try {
            if(Objects.nonNull(operationDTO)){
                setExplainMap(operationDTO);

                // 数据拼装成能够编辑的格式
                if (Objects.isNull(businessRuleDataPojo)) {
                    businessRuleDataPojo = getDataList(operationDTO);
                }
                Set<Long> formDataIdList = businessRuleDataPojo.getFormDataIdList();
                if (!isTrue(formDataIdList, operationDTO.getOperationType())) {
                    // 不满足条件，不执行
                    Integer count = 0;
                    if (CollectionsUtil.isNotEmpty(businessRuleDataPojo.getFormDataIdList())) {
                        count = formDataIdList.size();
                    }
                    if (count == 0) {
                        // 暂时无法确定是因为哪里报错的问题，先打下日志
                        LOG.error("corpid = " + corpid + ">condition=" + JSON.toJSONString(operationDTO.getConditionList()) + ">subCondition=" + JSON.toJSONString(operationDTO.getSubConditionList()));
                    }
                    setLog(operationDTO, BusinessRuleExecuteEnum.DATA_LARGE_ERROR.getMessage(), BusinessRuleExecuteEnum.DATA_LARGE_ERROR.getCode(), RuleOperationEnum.ONLY_UPDATE.getType(), count, 1);
                    return;
                }
                Integer result = 0;

                // 获取redis中数据，即有多少条数据正在执行业务规则
                List<Long> redisFormDataList = JSON.parseArray(paasRedisHelper.getValue(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE, key), Long.class);
                boolean include = false;
                if (Objects.nonNull(redisFormDataList)) {
                    // redis数据超过1000条时，直接加锁
                    include = redisFormDataList.size() >= 1000;
                    if (!include) {
                        for (Long item : redisFormDataList) {
                            if (businessRuleDataPojo.getFormDataIdList().contains(item)) {
                                include = true;
                                break;
                            }
                        }
                    }
                }


                // 如果已经有在处理的数据，则需要进行加锁处理
                boolean lock = (CollectionsUtil.isEmpty(redisFormDataList)
                        || include);
                if (lock) {
                    LOG.info("onlyUpdate businessRule need lock， key:" + key );
                    // 加锁：由公司id和表单id，拼合而成一个key，用于拦截“仅更新”，避免导入时数据数据混乱
                    // 出现问题的情况如下：如果是“仅更新”操作，且目标表单有符合条件的数据，并且是导入或者批量进来的，当前表单的数据会有多条符合条件，那么业务规则会执行更新操作
                    // 期望是如果操作中有计算操作，其最终值应该保证正确
                    // 不加锁的情况下，即错误的时候如果是“仅更新”操作的话，更新的值如果含有计算也会存在问题；
                    long startTime = DateTimeUtil.getLong();
                    if (paasRedisLock.tryLock(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE_LOCK, key, requestId, PaasRedisLock.TIMEOUT, PaasRedisLock.TIMEOUT, TimeUnit.MINUTES)) {
                        long endTime = DateTimeUtil.getLong();
                        long time = endTime - startTime;
                        LOG.info("onlyUpdate businessRule lock customer time， key:" + key + "-》time：" + time);
                        // 进入并发操作
                        Set<Long> formIdSet = businessRuleDataPojo.getFormDataIdList();
                        if (CollectionsUtil.isNotEmpty(redisFormDataList)) {
                            formIdSet.addAll(redisFormDataList);
                        }
                        paasRedisHelper.setValue4Set(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE, key, formIdSet, TimeConstant.SECONDS_PER_MINUTE);
                        result = update(operationDTO, businessRuleDataPojo) + result;
                        // 移掉已经执行的数据id
                        List<Long> redisDataList = JSON.parseArray(paasRedisHelper.getValue(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE, key), Long.class);
                        if (CollectionsUtil.isNotEmpty(redisDataList)) {
                            redisDataList.removeAll(businessRuleDataPojo.getFormDataIdList());
                            paasRedisHelper.setValue4Set(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE, key, new HashSet(redisDataList), TimeConstant.SECONDS_PER_MINUTE);
                        }

                        paasRedisLock.unlock(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE_LOCK, key, requestId);

                    } else {
                        // 记录日志
                        LOG.warn("onlyUpdate get lock failed key：" + key);
                        setLog(operationDTO, BusinessRuleExecuteEnum.GET_LOCK_ERROR.getMessage(), BusinessRuleExecuteEnum.GET_LOCK_ERROR.getCode(), RuleOperationEnum.ONLY_UPDATE.getType(),
                                1, 0);

                    }
                } else {
                    LOG.info("onlyUpdate businessRule not need lock， key:" + key );
                    paasRedisHelper.setValue4Set(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE, key, businessRuleDataPojo.getFormDataIdList(), TimeConstant.SECONDS_PER_MINUTE);
                    result = update(operationDTO, businessRuleDataPojo) + result;
                    // 执行完清掉redis中的数据
                    redisFormDataList = JSON.parseArray(paasRedisHelper.getValue(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE, key), Long.class);
                    if (CollectionsUtil.isNotEmpty(redisFormDataList)) {
                        redisFormDataList.removeAll(businessRuleDataPojo.getFormDataIdList());
                        Set<Long> formIdSet = new HashSet<>(redisFormDataList);
                        paasRedisHelper.setValue4Set(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE, key, formIdSet, TimeConstant.SECONDS_PER_MINUTE);
                    }
                }
                setLog(operationDTO, BusinessRuleExecuteEnum.SUCCESS.getMessage(), BusinessRuleExecuteEnum.SUCCESS.getCode(), RuleOperationEnum.ONLY_UPDATE.getType(), result, 1);

            }
            LOG.info("businessRule onlyUpdate update success");
        } catch (XbbException e) {
            paasRedisLock.unlock(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE_LOCK, key, requestId);
            throw e;
        } catch (Exception e) {
            paasRedisLock.unlock(RedisPrefixConstant.BUSINESS_RULE_ONLY_UPDATE_LOCK, key, requestId);
            LOG.error("onlyUpdateHelp.onlyUpdate业务规则仅更新出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    private Integer update(OperationDTO operationDTO, BusinessRuleDataPojo businessRuleDataPojo) throws XbbException {
        List<OperationsPojo> operations = operationDTO.getOperations();
        RuleTargetPojo ruleTargetPojo = operationDTO.getTarget();
        String corpid = operationDTO.getCorpid();
        Integer result;
        try {
            List<PaasFormDataEntityExt> formDataList = formDataHelp.getByDataIdList(businessRuleDataPojo.getFormDataIdList(), ruleTargetPojo.getLinkBusinessType(), ruleTargetPojo.getLinkSaasMark(), ruleTargetPojo.getFormId(), operationDTO.getCorpid());
            businessRuleDataPojo.setFormDataList(formDataList);
            List<? extends PaasFormSubDataEntity> subFormDataList = getSubDataList(corpid, ruleTargetPojo, businessRuleDataPojo.getSubFormDataIdList());
            businessRuleDataPojo.setSubFormDataList(subFormDataList);
            List<UpdateDataEntity> updateList = getUpdateDataList(operationDTO, businessRuleDataPojo);
            List<UpdateDataEntity> loggerList = new ArrayList<>(updateList);
            result = loggerList.size();
            // 判断字段是否可编辑暂时不要
            if(Objects.nonNull(operations) && CollectionsUtil.isNotEmpty(updateList)){
                if (Objects.equals(SaasMarkEnum.PAAS.getCode(), ruleTargetPojo.getLinkSaasMark())) {
                    paasFormDataModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                } else {
                    XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(ruleTargetPojo.getLinkBusinessType());
                    List<Long> updateIdList = updateList.stream().map(item -> item.getId()).collect(Collectors.toList());
                     switch (xbbRefTypeEnum) {
                        case CUSTOMER_MANAGEMENT:
                            // 客户
                            customerModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            //评分更新(业务规则修改客户信息 只编辑)
                            scoreCalculateService.asyncUpdateBatchDataScore(XbbRefTypeEnum.CUSTOMER_MANAGEMENT,corpid,updateIdList);
                            break;
                        case CONTACT:
                            // 联系人
                            contactModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case CUSTOMER_COMMUNICATE:
                            // 跟进记录
                            customerCommunicateModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case COMMUNICATE_PLAN:
                            // 访客计划
                            communicatePlanModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case SALES_OPPORTUNITY:
                            // 机会
                            opportunityModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case CONTRACT:
                            //合同订单
                            contractModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            //异步更新合同关联客户的合同最近签订时间
                            publicSeniorRuleHelp.asyncUpdateCustomerSignTime(updateList,corpid);
                            break;
                        case REFUND:
                            // 退货退款
                            refundModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case PRODUCT:
                            // 产品
                            productModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case QUOTATION:
                            // 报价单
                            quotationModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case PURCHASE:
                            // 采购合同
                            purchaseModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case SUPPLIER:
                            // 供应商
                            supplierModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case SUPPLIER_COMMUNICATE:
                            // 供应商跟进记录
                            supplierCommunicateModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case SUPPLIER_CONTACT:
                            // 供应商联系人
                            supplierContactModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case RETURNED_PURCHASE:
                            // 采购退货单
                            returnedPurchaseModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case BOM_BILL:
                            // bom单
                            bomBillModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case PRODUCTION_ORDER:
                            // 生产单
                            productionOrderModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case ASSEMBLE:
                            // 装配出入单
                            assembleModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case INSTOCK:
                        case PURCHASE_INSTOCK:
                        case OTHER_INSTOCK:
                        case REFUND_INSTOCK:
                        case RETURNED_MATERIEL_INSTOCK:
                        case PRODUCTION_INSTOCK:
                            // 入库单
                            instockModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case OUTSTOCK:
                        case CONTRACT_OUTSTOCK:
                        case OTHER_OUTSTOCK:
                        case RETURNED_PURCHASE_OUTSTOCK:
                        case PRODUCTION_MATERIEL_OUTSTOCK:
                            // 出库单
                            outstockModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case INVENTORY:
                            // 盘点单
                            inventoryModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case TRANSFER:
                            // 调拨单
                            transferModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case WAREHOUSE:
                            // 仓库
                            warehouseModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case WORK_ORDER:
                            // 工单
                            workOrderModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case PAYMENT:
                            paymentModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case PAYMENT_SHEET:
                            paymentSheetModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case PAY_PLAN:
                            payPlanModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case PAY_SHEET:
                            payPlanSheetModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case INVOICE:
                            invoiceModel.updateBatch(updateList, corpid, WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case PURCHASE_INVOICE:
                            purchaseInvoiceModel.updateBatch(updateList, corpid,  WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                        case CLUE:
                            clueModel.updateBatch(updateList, corpid,  WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            //更新评分(业务规则 只编辑)
                            scoreCalculateService.asyncUpdateBatchDataScore(XbbRefTypeEnum.CLUE,corpid,updateIdList);
                            break;
                        case MARKET_ACTIVITY:
                            marketActivityModel.updateBatch(updateList, corpid,  WriteRequest.RefreshPolicy.WAIT_UNTIL);
                        case COST_ADJUST:
                            costAdjustModel.updateBatch(updateList, corpid,  WriteRequest.RefreshPolicy.WAIT_UNTIL);
                            break;
                         case COMPETITOR:
                             competitorModel.updateBatch(updateList,corpid,WriteRequest.RefreshPolicy.WAIT_UNTIL);
                             break;
                        default:
                            break;
                    }
                }
                RuleBusinessLogDTO businessLogDTO = new RuleBusinessLogDTO(ruleTargetPojo, operations, formDataList,
                        operationDTO.getTargetExplain(), operationDTO.getCorpid(), operationDTO.getLoginUser(), operationDTO.getOperationType(), operationDTO.getPlatform(), operationDTO.getHttpHeader(), operationDTO.getBrowserInfo(), operationDTO.getIp(), operationDTO.getLocale());
                ruleBusinessLogger.writeLog(businessLogDTO, loggerList);

            }

        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("onlyUpdateHelp.update业务规则仅更新出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return result;
    }

    @Override
    public void onlyDelete(OperationDTO operationDTO) throws XbbException {
        try {
            BusinessRuleDataPojo businessRuleDataPojo  = getDataList(operationDTO);
            List<Long> dataIdList = new ArrayList<>(businessRuleDataPojo.getFormDataIdList());
            if(Objects.nonNull(operationDTO)){
                if (!isTrue(businessRuleDataPojo.getFormDataIdList(), operationDTO.getOperationType())) {
                    setLog(operationDTO, BusinessRuleExecuteEnum.DATA_LARGE_ERROR.getMessage(), BusinessRuleExecuteEnum.DATA_LARGE_ERROR.getCode(), RuleOperationEnum.ONLY_DELETE.getType(), dataIdList.size(), 1);
                    return;
                }
                Integer deleteId = dataIdList.size();
                String message = BusinessRuleExecuteEnum.SUCCESS.getMessage();
                Integer code =  BusinessRuleExecuteEnum.SUCCESS.getCode();
                Integer consumer = 1;
                if (CollectionsUtil.isNotEmpty(dataIdList)) {
                    setExplainMap(operationDTO);
                    RuleTargetPojo ruleTargetPojo = operationDTO.getTarget();
                    FormDataDeleteBatchDTO formDataDeleteBatchDTO = new FormDataDeleteBatchDTO();
                    BeanUtil.copyProperties(operationDTO, formDataDeleteBatchDTO);

                    formDataDeleteBatchDTO.setDataIdList(dataIdList);
                    formDataDeleteBatchDTO.setAppId(ruleTargetPojo.getAppId());
                    formDataDeleteBatchDTO.setMenuId(ruleTargetPojo.getMenuId());
                    formDataDeleteBatchDTO.setFormId(ruleTargetPojo.getFormId());
                    formDataDeleteBatchDTO.setSaasMark(ruleTargetPojo.getLinkSaasMark());
                    formDataDeleteBatchDTO.setBusinessType(ruleTargetPojo.getLinkBusinessType());
                    formDataDeleteBatchDTO.setIsBusinessRule(1);
                    FormDataDeleteBatchVO formDataDeleteBatchVO = listBatchService.deleteBatch(formDataDeleteBatchDTO);
                    deleteId = formDataDeleteBatchVO.getDeleteIds() == null ? dataIdList.size() : formDataDeleteBatchVO.getDeleteIds().size();
                    if (Objects.nonNull(formDataDeleteBatchVO) && CollectionsUtil.isNotEmpty(formDataDeleteBatchVO.getErrorDataList())) {
                        // 删除失败的原因（客户等有返回数据的）
                        LOG.info("businessRule onlyDelete not delete ：" + JSON.toJSONString(formDataDeleteBatchVO.getErrorDataList()));
                        message = formDataDeleteBatchVO.getErrorDataMemo();
                        deleteId = formDataDeleteBatchVO.getErrorDataList() == null ? 0 : formDataDeleteBatchVO.getErrorDataList().size();
                        code = BusinessRuleExecuteEnum.BUSINESS_ERROR.getCode();
                        consumer = 0;
                    }
                }
                setLog(operationDTO, message, code, RuleOperationEnum.ONLY_DELETE.getType(), deleteId, consumer);

                LOG.info("businessRule onlyDelete delete success");
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e){
            LOG.error("businessRuleService.onlyDelete业务规则仅删除出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public ScriptVO setWhiteList(BusinessRuleSetWhiteListDTO businessRuleSetWhiteListDTO) throws XbbException {
        try {
            Set<String> businessRuleCorpidList = new HashSet<>();
            List<String> businessRuleCorpid = businessRuleSetWhiteListDTO.getBusinessRuleCorpid();
            CompanyConfigEntity companyConfigEntity = companyConfigModel.getByConfigAlias(CompanyConfigEnum.BUSINESS_RULE_WHITE.getAlias(), "0");
            if (Objects.isNull(companyConfigEntity)) {
                businessRuleCorpidList.addAll(businessRuleCorpid);
            } else {
               List<String> list = JSON.parseArray(companyConfigEntity.getConfigValue(), String.class);
                if (Objects.equals(0, businessRuleSetWhiteListDTO.getAdd())) {
                    list.removeAll(businessRuleCorpid);
                } else {
                    list.addAll(businessRuleCorpid);
                }
                businessRuleCorpidList.addAll(list);
            }
            companyConfigModel.save("0", CompanyConfigEnum.BUSINESS_RULE_WHITE.getAlias(), CompanyConfigEnum.BUSINESS_RULE_WHITE.getName(), JSON.toJSONString(businessRuleCorpidList));
            paasRedisHelper.setValue(RedisPrefixConstant.BUSINESS_RULE, CompanyConfigEnum.BUSINESS_RULE_WHITE.getAlias(), JSON.toJSONString(businessRuleCorpidList), TimeConstant.SECONDS_PER_DAY);
        } catch (Exception e) {
            LOG.error("businessRuleService.setWhiteList 设置白名单出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        ScriptVO scriptVO = new ScriptVO();
        scriptVO.setMsg("success");
        return scriptVO;
    }

    /**
     * 执行日志记录
     * @param operationDTO 实体
     * @param message 日志信息
     * @param reason 日志信息标识
     * @param executeResult 执行结果
     * @param executeNum 执行条数
     * @param consumer 执行成功和失败 0：失败； 1：成功
     * @throws XbbException
     */

    private void setLog(OperationDTO operationDTO, String message, Integer reason, Integer executeResult, Integer executeNum, Integer consumer) throws XbbException {

        if (executeNum == 0) {
            message = BusinessRuleExecuteEnum.NO_DATA.getMessage();
            reason = BusinessRuleExecuteEnum.NO_DATA.getCode();
        }
        BusinessRuleLogSaveDTO businessRuleLogSaveDTO = new BusinessRuleLogSaveDTO(operationDTO.getSaasMark(), operationDTO.getBusinessType(), operationDTO.getFormId(), operationDTO.getDataId(),
                operationDTO.getCorpid(), operationDTO.getLoginUser(), operationDTO.getPlatform(), operationDTO.getHttpHeader(), operationDTO.getBrowserInfo(), operationDTO.getIp(), operationDTO.getLocale());
        businessRuleLogSaveDTO.setBusinessRuleInfoId(operationDTO.getBusinessRuleInfoId());
        businessRuleLogSaveDTO.setBusinessRuleType(operationDTO.getBusinessRuleType());
        businessRuleLogSaveDTO.setOperationType(operationDTO.getOperationType());
        businessRuleLogSaveDTO.setMessage(message);
        businessRuleLogSaveDTO.setReason(reason);
        businessRuleLogSaveDTO.setRedisKey("");
        businessRuleLogSaveDTO.setTarget(operationDTO.getTarget());
        businessRuleLogService.log(businessRuleLogSaveDTO, executeResult, executeNum, consumer);

    }

    /**
     * 判断是否可以更新
     * @param formDataList
     * @param type
     * @return
     */
    private Boolean isTrue(Set<Long> formDataList, Integer type) {
        // 删除和更新需要控制在100条以内；
        // 更新和新建可以为空，但是需要在100条以内
        if (Objects.isNull(formDataList)) {
            return false;
        }
        if (Objects.equals(RuleOperationEnum.UPDATE_AND_INSERT.getType(), type)) {
            return formDataList.size() <= PaasConstant.LIMIT_MAX_NUM;
        } else if (!Objects.equals(RuleOperationEnum.UPDATE_AND_INSERT.getType(), type)) {
            return CollectionsUtil.isNotEmpty(formDataList) && formDataList.size() <= PaasConstant.LIMIT_MAX_NUM;
        }
        return false;
    }


    private BusinessRuleDataPojo getDataList(OperationDTO operationDTO) throws XbbException{
        BusinessRuleDataPojo businessRuleDataPojo = new BusinessRuleDataPojo();
        List<PaasFormDataEntityExt> formDataList;
        try {
            // 获取权限内的数据
            formDataList = getDataListByEs(operationDTO, operationDTO.getConditionList());
            RuleTargetPojo target = operationDTO.getTarget();

            if (Objects.equals(RuleOperationEnum.UPDATE_AND_INSERT.getType(), operationDTO.getOperationType())
                    || Objects.equals(RuleOperationEnum.ONLY_UPDATE.getType(), operationDTO.getOperationType())) {

                boolean allowEditAfterFinished = paasProcessTemplateModel.getEditAfterFinished(target.getAppId(), target.getMenuId(), target.getFormId(), operationDTO.getLoginUser());
                // 清除掉审批通过后不允许编辑的数据
                removeInApprovedEdit(allowEditAfterFinished, formDataList);

                List<ConditionsEntityExt> subConditionList = operationDTO.getSubConditionList();
                // 当前表单子表单字段更新目标表单子表单字段：子表单搜索条件不为空且主字段的条件不为空，且能够搜到数据，则需要去检索子表单数据；
                //当前主字段更新目标表单子表单字段： 子表单搜索条件不为空且主字段的条件为空，则需要去检索子表单数据；
                boolean searchSubFormData = CollectionsUtil.isEmpty(operationDTO.getConditionList())
                        || (CollectionsUtil.isNotEmpty(formDataList) && CollectionsUtil.isNotEmpty(operationDTO.getConditionList()));
                if (CollectionsUtil.isNotEmpty(subConditionList) && searchSubFormData) {
                    Set<Long> parentIdList = new HashSet<>();
                    formDataList.forEach(item->{
                        parentIdList.add(item.getDataId());
                    });

                    List<? extends PaasFormSubDataEntity> subFormDataList = getSubDataListByEs(operationDTO, operationDTO.getSubConditionList(), parentIdList);

                    if (CollectionsUtil.isEmpty(formDataList)) {
                        // 如果主表单没有查到数据，需要根据子表单的父id去查下主表数据
                        Set<Long> parentDataIdList = new HashSet<>();
                        subFormDataList.forEach(item->parentDataIdList.add(item.getDataId()));
                        // 根据主表dataId查询数据
                        formDataList = getDataListByParentId(operationDTO, parentDataIdList);
                        // 清除掉审批通过后不允许编辑的数据
                        removeInApprovedEdit(allowEditAfterFinished, formDataList);
                    }
                    if (CollectionsUtil.isEmpty(formDataList) && CollectionsUtil.isEmpty(subFormDataList)) {
                        return businessRuleDataPojo;
                    }
                    Set<Long> parentResultList = new HashSet<>();
                    subFormDataList.forEach(item->{
                       Long parentId = item.getDataId();
                       parentResultList.add(parentId);
                    });

                    // 将子表单和主表进行交集处理，排除不满足条件的主表数据
                    formDataList.removeIf(formData -> !parentResultList.contains(formData.getDataId()));
                    if (CollectionsUtil.isNotEmpty(subFormDataList)) {
                        List<Long> idList = new ArrayList<>();
                        subFormDataList.forEach(item->idList.add(item.getId()));
                        businessRuleDataPojo.setSubFormDataIdList(idList);
                    }
                    businessRuleDataPojo.setSubFormDataList(subFormDataList);
                }
            }
            if (CollectionsUtil.isNotEmpty(formDataList)) {
                Set<Long> idList = new HashSet<>();
                formDataList.forEach(item->idList.add(item.getDataId()));
                businessRuleDataPojo.setFormDataIdList(idList);
            }
            businessRuleDataPojo.setFormDataList(formDataList);

        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("com.xbongbong.paas.service.impl.BusinessRuleServiceImpl.getDataList failer：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return businessRuleDataPojo;
    }

    private List<? extends PaasFormSubDataEntity> getSubDataList(String corpid, RuleTargetPojo target, List<Long> idList) throws XbbException{
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(StringConstant.CORPID, corpid);
        param.put(StringConstant.FORM_ID, target.getFormId());
        param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
        param.put(StringConstant.IDIN, idList);

        IndexTypeEnum indexTypeEnum = indexTypeModel.getSubIndexType(corpid, target.getLinkBusinessType(), target.getLinkSaasMark());
        return paasFormSubDataModel.getSubDataList(param, indexTypeEnum);
    }

    /**
     * 条件只有 主键id或者流水号
     * @param conditionList
     * @return
     */
    private static boolean onlyDataIdInCondition(List<ConditionsEntityExt> conditionList) {
        if (CollectionsUtil.isEmpty(conditionList) || conditionList.size() > BasicConstant.ONE) {
            return false;
        }
        for (ConditionsEntityExt item : conditionList) {
            // 流水号在数据库中没有加索引，先去掉
            boolean equal = Objects.equals(ConditionEnum.IN.getSymbol(), item.getSymbol()) || Objects.equals(ConditionEnum.EQUAL.getSymbol(), item.getSymbol());
            if (Objects.equals(item.getFieldType(), FieldTypeEnum.DATAID.getType()) && equal) {
                return true;
            }
        }
        return false;

    }
    /**
     *
     * @param allowEditAfterFinished
     * @param formDataList
     * @return void
     * @author 吴峰
     * @date 2020/10/10 16:14
     * @throws XbbException
     */
    private void removeInApprovedEdit(boolean allowEditAfterFinished, List<PaasFormDataEntityExt> formDataList) {
        Iterator<PaasFormDataEntityExt> iterator = formDataList.iterator();
        while (iterator.hasNext()) {
            PaasFormDataEntityExt formData = iterator.next();
            boolean edit = paasProcessTemplateModel.isApprovedEdit(allowEditAfterFinished, formData);
            if (!edit) {
                // 清除掉不允许编辑的数据
                iterator.remove();
            }
        }

    }

    /**
     * 获取需要更新的数据
     * @param operationDTO
     * @param businessRuleDataPojo
     * @return java.util.List<com.xbongbong.pro.domain.entity.UpdateDataEntity>
     * @author 吴峰
     * @date 2020/9/29 15:58
     * @throws XbbException
     */
    private List<UpdateDataEntity> getUpdateDataList(OperationDTO operationDTO, BusinessRuleDataPojo businessRuleDataPojo) throws XbbException {
        List<PaasFormDataEntityExt> formDataList = businessRuleDataPojo.getFormDataList();

        List<? extends PaasFormSubDataEntity> subFormDataList = businessRuleDataPojo.getSubFormDataList();
        Integer type = operationDTO.getType();
        if (Objects.equals(RuleVersionEnum.SIMPLE.getType(), type)) {
            // 简易版 对数据进行加/减
            return businessRuleSimpleService.getUpdateDataBySimple(formDataList, subFormDataList, operationDTO);
        } else if (Objects.equals(RuleVersionEnum.ADVANCED.getType(), type)) {
            // 高级版 根据公式进行操作
            return businessRuleAdvancedService.getUpdateDataByFormula(formDataList, subFormDataList, operationDTO);
        }
        return new ArrayList<>();
    }
    /**
     * 根据条件查询数据
     * @param operationDTO
     * @param conditionList
     * @return java.util.List<com.xbongbong.pro.domain.entity.UpdateDataEntity>
     * @author 吴峰
     * @date 2020/9/29 15:58
     * @throws XbbException
     */
    private List<PaasFormDataEntityExt> getDataListByEs(OperationDTO operationDTO, List<ConditionsEntityExt> conditionList) throws XbbException {
        if (CollectionsUtil.isEmpty(conditionList)) {
            return new ArrayList<>();
        }
        RuleTargetPojo target = operationDTO.getTarget();
        String corpid = operationDTO.getCorpid();

        if (onlyDataIdInCondition(conditionList)) {
            // 条件中只有主键id，则可以直接搜索数据库
            List<Long> dataIdList = null;
            for (ConditionsEntityExt item : conditionList) {
                if (Objects.equals(FieldTypeEnum.DATAID.getType(), item.getFieldType())) {
                    dataIdList = JSON.parseArray(JSON.toJSONString(item.getValue()), Long.class);
                }
            }
            // corpid会在下面的方法赋值
            Map<String, Object> param = new HashMap<>(BasicConstant.THREE);
            param.put("flowStatusIn", FlowStatusEnum.getStatisticType());
            param.put("start", 0);
            param.put("pageNum", PaasConstant.PAGE_NUM);

           return formDataHelp.getByCondition(dataIdList, param, target.getLinkBusinessType(), target.getLinkSaasMark(), target.getFormId(), corpid, null);
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();


        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
        boolQueryBuilder.filter(termQuery("formId", target.getFormId()));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));

        IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(corpid, target.getLinkBusinessType(), target.getLinkSaasMark());

        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        // 跟进记录不需要flowStatus条件，性能问题 by kaka
        if (!IDX_SAAS_CUSTOMER_COMMUNICATE.getCode().equals(indexTypeEnum.getCode())) {
            boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.PASS.getType(), FlowStatusEnum.NOT_NEED_APPROVAL.getType())));
        }
        // 地址查询条件封装
        List<List<ConditionsEntityExt>> shouldConditions = new ArrayList<>();
        AddressUtil.addressSearchCondition(conditionList, shouldConditions);
        // 地址查询条件封装
        EsUtil.parseShouldCondition(boolQueryBuilder, shouldConditions, "", corpid, target.getLinkBusinessType());
        EsUtil.parseCondition(boolQueryBuilder, conditionList, "", corpid, target.getLinkBusinessType());
        BoolQueryBuilder boolQuery = boolQuery();
        boolQueryBuilder.filter(boolQuery);
        EsUtil.setPage(sourceBuilder, 1, PaasConstant.PAGE_NUM);
        sourceBuilder.query(boolQueryBuilder);


        return paasEsModel.list(sourceBuilder, indexTypeEnum, new ArrayList<>(), 1, PaasConstant.PAGE_NUM);
    }

    /**
     * 根据主表dataId查询数据
     * @param operationDTO
     * @param dataIdList
     * @return java.util.List<com.xbongbong.pro.domain.entity.UpdateDataEntity>
     * @author 吴峰
     * @date 2020/9/29 15:58
     * @throws XbbException
     */
    private List<PaasFormDataEntityExt> getDataListByParentId(OperationDTO operationDTO, Set<Long> dataIdList) throws XbbException {
        if (CollectionsUtil.isEmpty(dataIdList)) {
            return new ArrayList<>();
        }
        RuleTargetPojo target = operationDTO.getTarget();

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        String corpid = operationDTO.getCorpid();
        IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(corpid, target.getLinkBusinessType(), target.getLinkSaasMark());

        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
        boolQueryBuilder.filter(termQuery("formId", target.getFormId()));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery(StringConstant.DATA_ID,  dataIdList));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
        BoolQueryBuilder boolQuery = boolQuery();
        boolQueryBuilder.filter(boolQuery);
        EsUtil.setPage(sourceBuilder, 1, PaasConstant.PAGE_NUM);
        sourceBuilder.query(boolQueryBuilder);


        return paasEsModel.list(sourceBuilder, indexTypeEnum, new ArrayList<>(), 1, PaasConstant.PAGE_NUM);
    }


    /**
     * 根据条件查询数据
     * @param operationDTO
     * @param conditionList
     * @param parentIdList
     * @return java.util.List<com.xbongbong.pro.domain.entity.UpdateDataEntity>
     * @author 吴峰
     * @date 2020/9/29 15:58
     * @throws XbbException
     */
    private List<PaasFormSubDataEntity> getSubDataListByEs(OperationDTO operationDTO, List<ConditionsEntityExt> conditionList, Set<Long> parentIdList) throws XbbException {
        if (CollectionsUtil.isEmpty(conditionList)) {
            return new ArrayList<>();
        }
        if (parentIdList.size() > PaasConstant.LIMIT_MAX_NUM) {
            // 如果大于这个数量的话，就没必要查了
            return new ArrayList<>();
        }
        RuleTargetPojo target = operationDTO.getTarget();


        BoolQueryBuilder boolQueryBuilder = boolQuery();
        String corpid = operationDTO.getCorpid();
        String parentAttr = operationDTO.getAttr();
        boolQueryBuilder.filter(termQuery(StringConstant.ATTR + StringConstant.POINT + StringConstant.KEY_WORD, parentAttr));
        if (CollectionsUtil.isNotEmpty(parentIdList)) {
            // 只有子表单，没有主数据，需要根据子表单的data_id反查主数据
            boolQueryBuilder.filter(termsQuery(StringConstant.DATA_ID, parentIdList));
        }
        IndexTypeEnum indexTypeEnum = indexTypeModel.getSubIndexType(corpid, target.getLinkBusinessType(), target.getLinkSaasMark());
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
        boolQueryBuilder.filter(termQuery("formId", target.getFormId()));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        EsUtil.parseCondition(boolQueryBuilder, conditionList, "", corpid, target.getLinkBusinessType());
        BoolQueryBuilder boolQuery = boolQuery();
        boolQueryBuilder.filter(boolQuery);

        List<PaasFormSubDataEntity> subDataList = paasFormSubDataEsModel.getSubDataList(boolQueryBuilder, indexTypeEnum, new ArrayList<>(), 1, 101, PaasFormSubDataEntity.class);
        if (subDataList.size() > PaasConstant.BUSINESS_RULE_SUB_FORM_MAX_LARGE) {
           return new ArrayList<>();
        }
        return subDataList;
    }







    /**
     * 不去存explain，直接在这里获取
     * @param operationDTO
     * @throws XbbException
     */
    private void setExplainMap(OperationDTO operationDTO) throws XbbException {
        Map<String, FieldAttrEntity> targetExplainMap = operationDTO.getTargetExplain() == null ? new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY) : operationDTO.getTargetExplain();
        if (Objects.isNull(targetExplainMap) || targetExplainMap.isEmpty()) {
            RuleTargetPojo ruleTargetPojo = operationDTO.getTarget();
            PaasFormExplainEntity paasFormExplainEntity = proFormHelp.getExplainEntity(operationDTO.getCorpid(), ruleTargetPojo.getFormId(), ruleTargetPojo.getLinkBusinessType());
            targetExplainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
            ProFormHelp.setDataIdAttr(targetExplainMap);
            operationDTO.setTargetExplain(targetExplainMap);
        }
        Map<String, FieldAttrEntity> thisExplainMap = operationDTO.getThisExplain() == null ? new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY) : operationDTO.getThisExplain();
        if (Objects.isNull(thisExplainMap) || thisExplainMap.isEmpty()) {
            PaasFormExplainEntity paasFormExplainEntity = proFormHelp.getExplainEntity(operationDTO.getCorpid(), operationDTO.getFormId(), operationDTO.getBusinessType());
            thisExplainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
            ProFormHelp.setDataIdAttr(thisExplainMap);
            operationDTO.setThisExplain(thisExplainMap);
        }
    }




}
